/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.cx1.service.impl;

import com.rits.cloning.Cloner;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import net.ricecode.similarity.JaroWinklerStrategy;
import net.ricecode.similarity.SimilarityStrategy;
import net.ricecode.similarity.StringSimilarityService;
import net.ricecode.similarity.StringSimilarityServiceImpl;
import org.apache.commons.lang.StringUtils;
import org.cx1.model.Listing;
import org.cx1.model.Photo;
import org.cx1.model.ds.MockDS;
import org.cx1.model.Place;
import org.cx1.model.utils.KPlaceTypeIDs;
import org.cx1.model.utils.ServiceResponse;
import org.cx1.service.api.IPhotoService;
import org.cx1.service.api.IPlaceService;
import org.cx1.service.utils.IDGenerator;

/**
 *
 * @author ECH
 */
public class MPlaceService implements IPlaceService {

    private IPhotoService photoService = new MPhotoService();
    
    private Cloner cloner = new Cloner();
    
    @Override
    public ServiceResponse<String> create(Place place) {
        ServiceResponse<String> response = new ServiceResponse<String>();
        String id = null;        
        try {            
            Place entry = new Place();
            id = IDGenerator.generateID();
            
            entry.setId(id);
            entry.setPlaceTypeID(place.getPlaceTypeID());
            
            entry.setTitle(place.getTitle());
            entry.setDescription(place.getDescription());
            entry.setShortDescription(place.getShortDescription());
            entry.setNotes(place.getNotes());
            
            entry.setAddress(place.getAddress());
            
            entry.setStreet(place.getStreet());
            entry.setBarangay(place.getBarangay());
            entry.setCity(place.getCity());
            entry.setRegion(place.getRegion());
            entry.setCountry(place.getCountry());
            
            entry.setZip(place.getZip());
            
            entry.setLat(place.getLat());
            entry.setLng(place.getLng());
            
            entry.setWikiURL(place.getWikiURL());
            
            entry.setPrimaryPhotoID(place.getPrimaryPhotoID());
            entry.setPhotoIDs(place.getPhotoIDs());
                        
            entry.setCityIDs(place.getCityIDs());
            entry.setDistrictIDs(place.getDistrictIDs());
            entry.setBuildingIDs(place.getBuildingIDs());
            entry.setVillageIDs(place.getVillageIDs());
                    
            entry.setActive(true);
            entry.setDateCreated(new Date());
            entry.setDateModified(new Date());
                        
            MockDS.getPlaces().add(entry);
            
            response.setResponse(id);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse("");
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<Place> read(String id) {
        ServiceResponse<Place> response = new ServiceResponse<Place>();
        Place place = null;
        try {            
            List<Place> records = MockDS.getPlaces();
            if (records != null && records.size() > 0) {
                for (Place record : records) {
                    if (StringUtils.equalsIgnoreCase(record.getId(), id)) {
                        place = record;
                        break;
                    }
                }
            }            
            populatePlaceAttributes(place);
            
            response.setResponse(place);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }
    
    @Override
    public ServiceResponse<Place> readShallow(String id) {
        ServiceResponse<Place> response = new ServiceResponse<Place>();
        Place place = null;
        
        try {            
            List<Place> records = MockDS.getPlaces();
            if (records != null && records.size() > 0) {
                for (Place record : records) {
                    if (StringUtils.equalsIgnoreCase(record.getId(), id)) {
                        place = record;
                        break;
                    }
                }
            }                        
            
            if (place.getCities() != null) {
                place.getCities().clear();                
            }
            if (place.getDistricts() != null) {
                place.getDistricts().clear();                
            }
            if (place.getBuildings() != null) {
                place.getBuildings().clear();                
            }
            if (place.getVillages() != null) {
                place.getVillages().clear();                
            }
            
            if (place.getListings() != null) {
                place.getListings().clear();                
            }
            
            response.setResponse(place);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }
    
    @Override
    public ServiceResponse<List<Place>> readAll(int offset, int limit) {
        ServiceResponse<List<Place>> response = new ServiceResponse<List<Place>>();
        List<Place> places = new ArrayList<Place>();
        try {            
            List<Place> records = MockDS.getPlaces();
            if (records != null && records.size() > 0) {
                if (offset == 0 && limit == 0) {
                    places.addAll(records);
                }
                else if (offset < records.size() && limit < records.size()) {
                    places.addAll( records.subList(offset, limit) );
                }              
            }            
            response.setResponse(places);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<Boolean> update(Place place) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {            
            Place targetPlace = null;
            String targetID = place.getId();            
            List<Place> records = MockDS.getPlaces();
            
            if ( !StringUtils.isEmpty(targetID) && records != null && records.size() > 0) {                
                //CX: find record
                for (Place record : records) {
                    if (StringUtils.equalsIgnoreCase(record.getId(), targetID)) {
                        targetPlace = record;
                        break;
                    }
                }                
                //CX: update dabase record
                if (targetPlace != null) {
                    targetPlace.setPlaceTypeID(place.getPlaceTypeID());
                    
                    targetPlace.setTitle(place.getTitle());
                    targetPlace.setDescription(place.getDescription());
                    targetPlace.setShortDescription(place.getShortDescription());
                    targetPlace.setNotes(place.getNotes());

                    targetPlace.setAddress(place.getAddress());
                    
                    targetPlace.setStreet(place.getStreet());
                    targetPlace.setBarangay(place.getBarangay());
                    targetPlace.setCity(place.getCity());
                    targetPlace.setRegion(place.getRegion());
                    targetPlace.setCountry(place.getCountry());

                    targetPlace.setZip(place.getZip());
            
                    targetPlace.setLat(place.getLat());
                    targetPlace.setLng(place.getLng());

                    targetPlace.setWikiURL(place.getWikiURL());
            
                    targetPlace.setPrimaryPhotoID(place.getPrimaryPhotoID());
                    targetPlace.setPhotoIDs(place.getPhotoIDs());  
                    
                    targetPlace.setCityIDs(place.getCityIDs());
                    targetPlace.setDistrictIDs(place.getDistrictIDs());
                    targetPlace.setBuildingIDs(place.getBuildingIDs());
                    targetPlace.setVillageIDs(place.getVillageIDs());
                    
                    targetPlace.setDateModified(new Date());            
                    success = true;
                }                
            }                
            response.setResponse(success);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<Boolean> delete(String id) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {            
            List<Place> records = MockDS.getPlaces();
            if (records != null && records.size() > 0) {
                
                for (int i = 0; i < records.size(); i++) {
                    Place record = records.get(i);
                    
                    if (StringUtils.equalsIgnoreCase(record.getId(), id)) {
                        records.remove(i);
                        success = true;
                        break;
                    }
                }
            }            
            response.setResponse(success);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<String> readIDByTitle(String title) {
        ServiceResponse<String> response = new ServiceResponse<String>();
        String id = "";
        try {            
            List<Place> records = MockDS.getPlaces();
            if (records != null && records.size() > 0) {
                for (Place record : records) {
                    if (StringUtils.equalsIgnoreCase(record.getTitle(), title)) {
                        id = record.getId();
                        break;
                    }
                }
            }            
            response.setResponse(id);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse("");
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<List<Place>> readAllByType(String placeTypeID, int offset, int limit) {
        ServiceResponse<List<Place>> response = new ServiceResponse<List<Place>>();
        List<Place> places = new ArrayList<Place>();
        try {            
            List<Place> records = MockDS.getPlaces();
            List<Place> typeRecords = new ArrayList<Place>();
            
            if (records != null && records.size() > 0) {
                
                for (Place record : records) {
                    if (StringUtils.equalsIgnoreCase(record.getPlaceTypeID(), placeTypeID)) {
                        typeRecords.add(record);
                    }
                }
                
                if (typeRecords != null && typeRecords.size() > 0) {
                    if (offset == 0 && limit == 0) {
                        places.addAll(typeRecords);
                    }
                    else if (offset < typeRecords.size() && limit < typeRecords.size()) {
                        places.addAll( typeRecords.subList(offset, limit) );
                    }            
                    else {
                        places.addAll(typeRecords);
                    }                    
                }
            }            
            response.setResponse(places);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    private void populatePlaceAttributes(Place place) {
        if (place != null) {
            
            //CX: populate cities
            if (place.getCities() == null) {
                place.setCities(new ArrayList<Place>());
            }
            place.getCities().clear();
            if (place.getCityIDs() != null && place.getCityIDs().size() > 0) {
                ServiceResponse<Place> sr1 = null;

                for (String placeID : place.getCityIDs()) {
                    sr1 = this.readShallow(placeID);

                    if (sr1.isSuccessful() && sr1.getResponse() != null) {
                        place.getCities().add(sr1.getResponse());
                    }
                }                    
            }                
            
            //CX: populate districts
            if (place.getDistricts() == null) {
                place.setDistricts(new ArrayList<Place>());
            }
            place.getDistricts().clear();
            if (place.getDistrictIDs()!= null && place.getDistrictIDs().size() > 0) {
                ServiceResponse<Place> sr1 = null;

                for (String placeID : place.getDistrictIDs()) {
                    sr1 = this.readShallow(placeID);

                    if (sr1.isSuccessful() && sr1.getResponse() != null) {
                        place.getDistricts().add(sr1.getResponse());
                    }
                }                    
            }          
            
            //CX: populate buildings
            if (place.getBuildings() == null) {
                place.setBuildings(new ArrayList<Place>());
            }
            place.getBuildings().clear();
            if (place.getBuildingIDs()!= null && place.getBuildingIDs().size() > 0) {
                ServiceResponse<Place> sr1 = null;

                for (String placeID : place.getBuildingIDs()) {
                    sr1 = this.readShallow(placeID);

                    if (sr1.isSuccessful() && sr1.getResponse() != null) {
                        place.getBuildings().add(sr1.getResponse());
                    }
                }                    
            }        
            
            //CX: populate villages
            if (place.getVillages() == null) {
                place.setVillages(new ArrayList<Place>());
            }
            place.getVillages().clear();
            if (place.getVillageIDs()!= null && place.getVillageIDs().size() > 0) {
                ServiceResponse<Place> sr1 = null;

                for (String placeID : place.getVillageIDs()) {
                    sr1 = this.readShallow(placeID);

                    if (sr1.isSuccessful() && sr1.getResponse() != null) {
                        place.getVillages().add(sr1.getResponse());
                    }
                }                    
            }        
            
            //CX: populate attributes
            place.setDisplayCity(buildDisplayCity(place));           
            
            //CX: populate photos
            place.getPhotos().clear();                
            if (place.getPhotoIDs() != null && place.getPhotoIDs().size() > 0) {
                ServiceResponse<Photo> sr2 = null;

                for (String photoID : place.getPhotoIDs()) {
                    sr2 = this.photoService.read(photoID);                        
                    if (sr2.isSuccessful() && sr2.getResponse() != null) {
                        place.getPhotos().add(sr2.getResponse());
                    }
                }                    
            }
            
            //CX: populate primary            
            if (place.getPhotos() != null && place.getPhotos().size() > 0) {
                place.setPrimaryPhoto(place.getPhotos().get(0));
            }
        }            
    }

    //CX: threshold = 0.9
    @Override
    public ServiceResponse<Place> readClosestMatch(String placeTypeID, String title) {
        ServiceResponse<Place> response = new ServiceResponse<Place>();
        Place place = null;
        try {            
            List<Place> records = MockDS.getPlaces();
            if (records != null && records.size() > 0) {
                for (Place record : records) {
                    if (StringUtils.equals(record.getPlaceTypeID(), placeTypeID)) {
                        SimilarityStrategy strategy = new JaroWinklerStrategy();
                        StringSimilarityService service = new StringSimilarityServiceImpl(strategy);
                        double score = service.score(record.getTitle(), title);    
                        
                        if (score >= 0.9) {
                            place = record;
                            break;
                        }
                    }
                }
            }                        
            response.setResponse(place);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    
    private String buildDisplayCity(Place place) {
        String displayCity = "";    
        try {
            if (!StringUtils.isEmpty(place.getCity())) {
                displayCity = place.getCity();
                displayCity = displayCity.replaceAll("city", "");
                displayCity = displayCity.replaceAll("City", "");
                displayCity = displayCity.trim();
            }             
        } catch (Exception ex) {
            
        }   
        return displayCity;
    }
    
    private Place clonePlace(Place place) {
        return cloner.deepClone(place);
    }
    
    public static void main (String[] argv) {        
        IPlaceService placeService = new MPlaceService();
        ServiceResponse<Place> sr1 = placeService.readClosestMatch(KPlaceTypeIDs.BUILDING, "Grand Soho");
        System.out.println("CX: " + sr1.getResponse().getTitle());
        System.out.println("CX: lat- " + sr1.getResponse().getLng());
        System.out.println("CX: lng- " + sr1.getResponse().getLat());
    }

    @Override
    public ServiceResponse<Boolean> incrementImpressions(String id) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public ServiceResponse<Boolean> incrementViews(String id) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
    
}
